# -*- encoding: utf-8 -*-
"""
@File    : policy.py
@Author  : lilong
@Time    : 2021/12/27 10:26 上午
"""

"""
参考：https://www.jianshu.com/p/e535d23dab0e

策略模式是什么？
简单来说，策略模式就是把变化的行为抽离出来，单独封装，使用的时候，直接调用这些封装好的行为即可。
以我们的游戏项目为例，我们可以把fire()行为拿出来。

现在我们来看下之前面临的问题是否解决了呢？

（1）如果将来的fire行为有更改，我们需要更改所有涉及到的飞机类型
目前来看如果将来的某个fire行为需要更改，我们只需要修改特定的FireAction子类即可，不需要再更改所有的子飞机类型

（2）我们无法在运行时动态的更改某个飞机类型的fire行为
我们可以根据需要在fire的时候动态的更改fire行为，只需要传递特定的FireAction类型即可

（3）另外如果我们将来想让某些飞机没有fire行为，目前的继承方式是无法做到的
我们的CTypePlane已经没有fire行为了

这样看来我们之前面临的三个问题都通过策略模式解决了。而且将来如果新增策略（即fire行为）时，也无需担心之前的代码，
只需要重新实现一个FireAction子类即可，那么下面让我们总结下什么情况下使用策略模式吧。

出现如下情况时有必要采用策略模式：

什么情况下使用？
（1）当一个类型可能会有很多种子类，且这些子类的某些行为相同，某些行为不相同
（2）子类的行为需要在运行时更改
这时就有必要采用策略模式将不同的行为定义成不同的“策略”，同时通过组合的方式来使用这些“策略”，这也是设计原则之一，即能用组合就不要使用继承

什么情况下不用？
学习设计模式最忌讳过度使用，所以如果当你确定不会有很多子类，也不需要动态更改行为时就不需要使用策略模式。
这涉及另外一个设计原则，凡是不使用设计模式也能很好解决问题的时候就不要使用设计模式，这个是我说的。


"""


class FireAction(object):
    """定义fire基类"""

    def fire(self):
        pass


class SpeedFire(FireAction):
    """定义速射子弹"""

    def fire(self):
        pass


class ArmorPiercerFire(FireAction):
    """定义穿甲弹行为"""

    def fire(self):
        pass


# ------------现在我们需要在我们的Plane当中加入fire行为---------
class Plane(object):
    def __init__(self, fire_action=None):
        self.color = 'black'
        self.life_left = 100
        self.fire_action = fire_action

    def turn(self, direction):
        """用于实现飞机的转向"""
        pass


# -----------------子类的实现-------------------
class ATypePlane(Plane):
    def __init__(self, fire_action=None):
        if fire_action is None or (not isinstance(fire_action, FireAction)):
            fire_action = ArmorPiercerFire()  # 默认使用ArmorPiercerFire

        super(ATypePlane, self).__init__(fire_action)

    def fire(self, fire_action=None):
        if fire_action is not None and isinstance(fire_action, FireAction):
            self.fire_action = fire_action
        self.fire_action.fire()


# -----------使用子类的程序可能如下-----------

# 没有fire行为的飞机
class CTypePlane(Plane):
    def __init__(self):
        super(CTypePlane, self).__init__()

